package com.techbh.ridecall;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
import com.techbh.ridecall.BuscarLocalActivity.MapOverlay;

public class BuscarLocalActivity extends MapActivity {

	MapView mapView; 	//visao do mapa
	MapController mc;	//controlador do mapa
	GeoPoint p;	//ponto geografico
	GeoPoint pAnt;	//ponto tocado anteriormente  

	Double default_lat = -19.91905;
	Double default_lng = -43.93853;

	//Classe necessaria para sobrepor imagens/marcas no mapa
	class MapOverlay extends com.google.android.maps.Overlay{

		public Projection pj;

		private String APPTAG = "RideCall";

		private static final int T_INFO = 100;
		private static final int T_CONFIRMA = 200;


		boolean movimentou = false;
		long startTime = 0;
		long endTime = 0;

		double startX = 0;
		double startY = 0;
		double endX = 0;
		double endY = 0;

		GeoPoint startPoint;
		GeoPoint endPoint;		

		@Override
		public boolean draw(Canvas canvas, MapView mapView, 
				boolean shadow, long when)  {
			super.draw(canvas, mapView, shadow);                   

			pj = mapView.getProjection(); 

			// traduz as coordenadas do GeoPoint para posição na tela 
			Point screenPts = new Point();
			pj.toPixels(p, screenPts);

			/*
			 * Escondendo enquanto eu não souber atualizar no ponto tocado * /
      Bitmap bmp = BitmapFactory.decodeResource(
          getResources(), R.drawable.androidmarker);            
      canvas.drawBitmap(bmp, screenPts.x, screenPts.y-50, null);
      /* */

			//Log.i(APPTAG, "Draw do overlay no ponto" + p.getLatitudeE6() );

			return true;
		}

		public boolean onTouchEvent(MotionEvent event, MapView mapView){
			String endereco = "";

			int width = mapView.getWidth() / 20 ;
			int height = mapView.getHeight() / 20;
			int limiar_movimento = (width + height) / 4;

			GeoPoint p = mapView.getProjection().fromPixels(
					(int) event.getX(),
					(int) event.getY());

			/*
  		Toast.makeText(getBaseContext(), "Ponto tocado: " + 
  				p.getLatitudeE6() / 1E6 + "," + 
  				p.getLongitudeE6() /1E6 , 
  				Toast.LENGTH_SHORT).show();
			 */

			String latS = "lat:" + p.getLatitudeE6() / 1E6;
			String lngS = "lng:" + p.getLongitudeE6() / 1E6;

			Context ctx = getBaseContext();

			if(event.getAction() == MotionEvent.ACTION_DOWN){
				//grava quando começou o movimento
				movimentou = false;
				startTime = event.getEventTime();
				startPoint = p;
				startX = (double) event.getX();
				startY = (double) event.getY();

				Log.i(APPTAG, "Pressionou a tela em "+ latS + ", " + lngS );

			} else if(event.getAction() == MotionEvent.ACTION_MOVE){
				//Se o mapa está sendo movimentado então descarta o ponto
				movimentou = true;

				//@todo ajustar o ripple para evitar tremulações da mão em dispositivos muito sensiveis
				//Log.w(APPTAG, "Movimentando o mapa em "+ latS + ", " + lngS );
				Log.w(APPTAG, "Movimentando o mapa " );

			} else if(event.getAction() == MotionEvent.ACTION_UP){

				Log.i(APPTAG, "Liberou a tela em "+ latS + ", " + lngS );

				endX = (double) event.getX();
				endY = (double) event.getY();
				endPoint = p;

				double mdiff = Math.sqrt( Math.pow(startX - endX, 2) + Math.pow(startY - endY, 2) );
				boolean moveu_pouco = mdiff < (double) limiar_movimento; 
				Log.i(APPTAG, "variacao total= " + mdiff + " moveu pouco = " + moveu_pouco);


				if (!movimentou || moveu_pouco){
					//record the end time
					endTime = event.getEventTime();

					endereco = geocodeReverse(p);

					//testa a duração (em ms) do pressionamento
					if(endTime - startTime < T_INFO){

						Log.i(APPTAG, "Mostra o endereço = tempo > t_info em "+ latS + ", " + lngS );

						//Mostra o endereço ou as coordenadas
						Toast.makeText(ctx, endereco, Toast.LENGTH_SHORT ).show();


						//significa que foi tratado por essa função e não será propagado
						//onTap não funcionará
						return true; 

					} else if(endTime - startTime > T_CONFIRMA){
						Log.i(APPTAG, "Confirma o ponto pressionado = tempo > t_confirma em " + latS + ", " + lngS );

						endereco = geocodeReverse(endPoint);

						AlertDialog.Builder builder = new AlertDialog.Builder(BuscarLocalActivity.this);
						//builder.setMessage("Confirma o local[ " + latS + ", " + lngS )
						builder.setMessage("Confirma \n" + endereco + " ?" )
						.setCancelable(false)
						.setPositiveButton("Sim", new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {

								String endereco = geocodeReverse(endPoint);
								confirmaPonto(endPoint, endereco);

							}
						})
						.setNegativeButton("Não", new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								dialog.cancel();
							}
						});
						AlertDialog alert = builder.create();
						alert.show();

						return true; //true = evento foi tratado, não propagar

					} else { 
						//TODO Tempo bem curto, fazer algo ?
						Log.i(APPTAG, "Tempo entre T_INFO e T_CONFIRMA ");
						Log.i(APPTAG, latS + ", " + lngS );

					}        	

				} else {
					//Não precisa fazer nada
					Log.i(APPTAG, "Movimentou o mapa, então não será feito nada ");
					Log.i(APPTAG, latS + ", " + lngS );

					//TODO verificar se precisa do return true aqui

				}
			}


			return false;
		}


		/* Tratamento para duplo clique
		 * Retorna:
		 * false = indica que não foi tratado, e o sistema deve propagar
		 * true = a função tratou, então não precisa propagar o evento
		 * */
		//ver mais opções aqui: http://developer.android.com/resources/tutorials/views/hello-mapview.html
		@Override
		public boolean onTap(GeoPoint p, MapView mapView){

			Float lat = (float) (p.getLatitudeE6() / 1E6);
			Float lng = (float) (p.getLatitudeE6() / 1E6);

			Log.i("RideCall", "onTap em lat:" + lat + ", lng" + lng );

			//Comportamento similar ao google maps, facilita uso do aplicativo
			mapView.getController().zoomIn();

			//Melhora se eu der o animate depois ?
			mapView.getController().animateTo(p); //fica razoável

			return false;
		}    


		public String geocodeReverse(GeoPoint p){
			String address = "";

			Geocoder geoCoder = new Geocoder(getBaseContext(), Locale.getDefault());
			try {
				List<Address> addresses = geoCoder.getFromLocation(
						p.getLatitudeE6()  / 1E6, 
						p.getLongitudeE6() / 1E6, 1);

				if (addresses.size() > 0){
					for (int i=0; i<addresses.get(0).getMaxAddressLineIndex(); i++){
						//Tratar somente o seguinte: rua numero, cidade, pais ?
						address += addresses.get(0).getAddressLine(i) + "\n";
					}
				}

				//Toast.makeText(getBaseContext(), address, Toast.LENGTH_SHORT).show();
			}
			catch (IOException e) {                
				//e.printStackTrace();
				Log.w("RideCall - reverseGeocode", e.getMessage());
			}       	
			return address;
		}


	} 	


	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.mapa);

		mapView = (MapView) findViewById(R.id.viewMapa);
		mapView.setBuiltInZoomControls(true);		//controle de zoom 

		//Controller do mapView
		mc = mapView.getController();


		/* Obtem a posicao atual do usuario usando LocationManager
		 * .NETWORK_PROVIDER + um monte de codigo
		 * .GPS_PROVIDER + um monte de codigo 
		 * ou um valor padrão
		 */

		double lat = default_lat;
		double lng = default_lng;

		p = new GeoPoint(
				(int) (lat * 1E6), 
				(int) (lng * 1E6));


		//movimenta o mapa para nova posicao
		mc.animateTo(p);

		/* Zoom apropriado
		 * 5 Brazil + principais capitais 
		 * 8 Minas
		 * 10 Grande BH
		 * 12 Anel rodoviario
		 * 13 Grandes Bairros
		 * 14 Bairros
		 * 15 Avenidas "Locais"
		 * 16 Rua (bom para escolher o local que se deseja marcar )
		 * 17 Quarteiroes
		 * 18 Quarteirão
		 */
		mc.setZoom(16);



		//---Add a location marker---
		MapOverlay mapOverlay = new MapOverlay();
		List<Overlay> listOfOverlays = mapView.getOverlays();
		listOfOverlays.clear();
		listOfOverlays.add(mapOverlay);		


		mapView.invalidate();


	}


	public void confirmaPonto(GeoPoint p, String endereco) {

		Bundle b = new Bundle();
		//b.putParcelableArray("location", local);

		b.putDouble("lat", (double) (p.getLatitudeE6() / 1E6));
		b.putInt("latI", p.getLatitudeE6() );

		b.putDouble("lng", (double) (p.getLongitudeE6() /1E6));
		b.putInt("lngI", p.getLongitudeE6() );

		b.putString("local", "" + (p.getLatitudeE6() / 1E6) + ", " + (p.getLongitudeE6() /1E6));
		b.putString("endereco", endereco);

		Intent dados = new Intent();
		dados.setAction("confirmar");
		dados.putExtras(b);

		setResult(RESULT_OK, dados );

		finish();

	}


	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}

}
